package com.timebank.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.timebank.common.core.constant.*;
import com.timebank.common.core.constant.message.MessageTypeConstant;
import com.timebank.common.core.constant.rabbitmq.exchange.ExchangeConstant;
import com.timebank.common.core.constant.rabbitmq.routingkey.RoutingKeyConstant;
import com.timebank.common.core.exception.captcha.CaptchaException;
import com.timebank.common.core.web.pojo.AjaxResult;
import com.timebank.common.redis.service.RedisService;
import com.timebank.system.pojo.SysUser;
import com.timebank.common.core.exception.ServiceException;
import com.timebank.common.core.utils.StringUtils;
import com.timebank.common.core.utils.bean.BeanValidators;
import com.timebank.common.security.utils.SecurityUtils;
import com.timebank.system.mapper.*;
import com.timebank.system.pojo.dto.BindEmailDTO;
import com.timebank.system.pojo.dto.RealNameDTO;
import com.timebank.system.pojo.entity.ContractMessage;
import com.timebank.system.pojo.entity.RealName;
import com.timebank.system.pojo.vo.RealNameVO;
import com.timebank.system.service.ISysConfigService;
import com.timebank.system.service.ISysUserService;
import com.timebank.timecoin.pojo.entity.User;
import io.swagger.annotations.ApiOperation;
import org.aspectj.weaver.loadtime.Aj;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.annotation.Resource;
import javax.validation.Validator;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 用户 业务层处理
 * 
 * @author shiliuyinzhen
 */
@Service
public class SysUserServiceImpl implements ISysUserService {

    private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);

    @Resource
    private SysUserMapper userMapper;

    @Resource
    private RealNameMapper realNameMapper;

    @Resource
    private ISysConfigService configService;

    @Resource
    protected Validator validator;
    @Resource
    private RedisService redisService;

    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 根据条件分页查询用户列表
     * 
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    public List<SysUser> selectUserList(SysUser user) {
        return userMapper.selectUserList(user);
    }

    /**
     * 通过用户名查询用户
     * 
     * @param userName 用户名
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByUserName(String userName) {
        return userMapper.selectUserByUserName(userName);
    }

    /**
     * 通过用户ID查询用户
     * 
     * @param userId 用户ID
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserById(Long userId)
    {
        return userMapper.selectUserById(userId);
    }

    /**
     * 校验用户名称是否唯一
     * 
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public boolean checkUserNameUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkUserNameUnique(user.getUserName());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param user 用户信息
     * @return
     */
    @Override
    public boolean checkPhoneUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkPhoneUnique(user.getPhone());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验email是否唯一
     *
     * @param user 用户信息
     * @return
     */
    @Override
    public boolean checkEmailUnique(SysUser user) {
        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkEmailUnique(user.getEmail());
        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验用户是否允许操作
     * 
     * @param user 用户信息
     */
    @Override
    public void checkUserAllowed(SysUser user) {
        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) {
            throw new ServiceException("不允许操作超级管理员用户");
        }
    }

    /**
     * 新增保存用户信息
     * 
     * @param sysUser 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertUser(SysUser sysUser) {
        // 新增用户信息
        int row = userMapper.insertUser(sysUser);
        return row;
    }

    /**
     * 注册用户信息
     * 
     * @param sysUser 用户信息
     * @return 结果
     */
    @Override
    public boolean registerUser(SysUser sysUser) {
        int row = userMapper.insertUser(sysUser);
        if (row > 0){
            //创建fabric账户
            User user = User.builder()
                    .userId(sysUser.getUserId())
                    .userName(sysUser.getUserName())
                    .timeCoin(0)
                    .build();
            //发送消息，异步处理
            ContractMessage msg = ContractMessage.builder()
                    .senderId(999L)
                    .senderName("system")
                    .getterId(999L)
                    .title("创建fabric用户")
                    .content("创建fabric用户：" + user)
                    .typeId(MessageTypeConstant.CONTRACT_USER_ADD)
                    .user(user)
                    .build();
            //将消息转换为json格式
            String msgJSON = JSON.toJSONString(msg);
            //发出通知
            rabbitTemplate.convertAndSend(ExchangeConstant.CONTRACT_MESSAGE_EXCHANGE, RoutingKeyConstant.CONTRACT_MESSAGE_ROUTING_KEY,msgJSON);
        }
        return row > 0;
    }

    /**
     * 修改保存用户信息
     * 
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateUser(SysUser user) {
        Long userId = user.getUserId();
        return userMapper.updateUser(user);
    }

    /**
     * 修改用户状态
     * 
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUserStatus(SysUser user) {
        return userMapper.updateUser(user);
    }

    /**
     * 修改用户基本信息
     * 
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUserProfile(SysUser user) {
        return userMapper.updateUser(user);
    }

    /**
     * 修改用户头像
     * 
     * @param userName 用户名
     * @param avatar 头像地址
     * @return 结果
     */
    @Override
    public boolean updateUserAvatar(String userName, String avatar) {
        return userMapper.updateUserAvatar(userName, avatar) > 0;
    }

    /**
     * 重置用户密码
     * 
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int resetPwd(SysUser user) {
        return userMapper.updateUser(user);
    }

    /**
     * 重置用户密码
     * 
     * @param userName 用户名
     * @param password 密码
     * @return 结果
     */
    @Override
    public int resetUserPwd(String userName, String password) {
        return userMapper.resetUserPwd(userName, password);
    }

    /**
     * 通过用户ID删除用户
     * 
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserById(Long userId) {
        return userMapper.deleteUserById(userId);
    }

    /**
     * 批量删除用户信息
     * 
     * @param userIds 需要删除的用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserByIds(Long[] userIds) {
        for (Long userId : userIds) {
            checkUserAllowed(new SysUser(userId));
        }
        return userMapper.deleteUserByIds(userIds);
    }

    /**
     * 导入用户数据
     * 
     * @param userList 用户数据列表
     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据
     * @param operName 操作用户
     * @return 结果
     */
    @Override
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
        if (StringUtils.isNull(userList) || userList.size() == 0) {
            throw new ServiceException("导入用户数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        String password = configService.selectConfigByKey("sys.user.initPassword");
        for (SysUser user : userList) {
            try {
                // 验证是否存在这个用户
                SysUser u = userMapper.selectUserByUserName(user.getUserName());
                if (StringUtils.isNull(u)) {
                    BeanValidators.validateWithException(validator, user);
                    user.setPassword(SecurityUtils.encryptPassword(password));
                    user.setCreateBy(operName);
                    userMapper.insertUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
                } else if (isUpdateSupport) {
                    BeanValidators.validateWithException(validator, user);
                    checkUserAllowed(u);
                    user.setUserId(u.getUserId());
                    user.setUpdateBy(operName);
                    userMapper.updateUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }


    /**
     * 批量支付时间币
     * @param userIds
     * @return
     */
    @Override
    public int payTimeCoinByIds(List<Long> userIds,Integer timeCoin) {
        return userMapper.payTimeCoinByIds(userIds,timeCoin);
    }

    /**
     * 批量获取用户信息
     *
     * @param userIds
     * @return
     */
    @Override
    public List<SysUser> getUserByIds(Long[] userIds) {
        return userMapper.getUserByIds(userIds);
    }

    /**
     * 根据邮箱获取用户信息
     * @param email
     * @return
     */
    @Override
    public SysUser getUserByEmail(String email) {
        return userMapper.getUserByEmail(email);
    }

    /**
     * 绑定邮箱
     * @param bindEmailDTO
     * @return
     */
    @Override
    public AjaxResult bindEmail(BindEmailDTO bindEmailDTO) {
        String email = bindEmailDTO.getEmail();
        String emailCode = bindEmailDTO.getEmailCode();
        //如果是邮箱和验证码登录
        if (email == null || email == ""){
            throw new ServiceException("邮箱不能为空");
        }
        //校验验证码
        if (StringUtils.isEmpty(emailCode)) {
            throw new CaptchaException("验证码不能为空");
        }
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + email;
        String captcha = redisService.getCacheObject(verifyKey);

        if (captcha == null || captcha == "") {
            throw new CaptchaException("验证码已失效");
        }
        if (!emailCode.equals(captcha)) {
            throw new CaptchaException("验证码错误");
        }
        //查询用户信息
        SysUser user = userMapper.getUserByEmail(email);
        if (user != null) {
            throw new ServiceException("邮箱：" + email + " 已被绑定");
        }
        //删除验证码缓存
        redisService.deleteObject(verifyKey);
        //更新用户信息
        Long userId = SecurityUtils.getUserId();
        return userMapper.updateUserEmail(userId,email) > 0 ?
                AjaxResult.success("绑定成功") : AjaxResult.error("绑定失败");
    }

    /**
     * 提交实名认证信息
     * @param realNameDTO
     * @return
     */
    @Override
    public AjaxResult bindRealName(RealNameDTO realNameDTO) {
        RealName realName = RealName.builder()
                .idCard(realNameDTO.getIdCard())
                .realName(realNameDTO.getRealName())
                .userId(SecurityUtils.getUserId())
                .status(StatusConstant.WAITING)
                .picture(realNameDTO.getPicture())
                .createBy("system")
                .createTime(LocalDateTime.now())
                .remark("用户提交材料")
                .build();
        return realNameMapper.addRealName(realName) > 0 ?
                AjaxResult.success("提交成功") : AjaxResult.error("提交失败");
    }

    /**
     * 修改实名认证信息
     *
     * @param realNameId
     * @param realNameDTO
     * @return
     */
    @Override
    public AjaxResult updateRealName(Long realNameId, RealNameDTO realNameDTO) {
        RealName realName = RealName.builder()
                .id(realNameId)
                .idCard(realNameDTO.getIdCard())
                .realName(realNameDTO.getRealName())
                .userId(SecurityUtils.getUserId())
                .status(StatusConstant.WAITING)
                .picture(realNameDTO.getPicture())
                .updateBy(SecurityUtils.getUsername())
                .updateTime(LocalDateTime.now())
                .remark("用户修改材料")
                .build();
        return realNameMapper.updateRealName(realName) > 0 ?
                AjaxResult.success("修改成功") : AjaxResult.error("修改失败");
    }

    /**
     * 实名认证审核通过
     * @param realNameId
     * @return
     */
    @Override
    public AjaxResult approveRealName(Long realNameId) {
        //校验 审核实名认证信息 权限
        checkUpdateRealNameStatusPermission();
        RealName realName = RealName.builder()
                .id(realNameId)
                .status(StatusConstant.ENABLE)
                .updateBy(SecurityUtils.getUsername())
                .updateTime(LocalDateTime.now())
                .remark("实名认证审核通过")
                .build();
        int row = realNameMapper.updateRealName(realName);
        if (row > 0){
            //查询实名认证信息
            RealNameVO realNameVO = realNameMapper.getRealNameById(realNameId);
            if (realNameVO == null){
                throw new ServiceException("未找到实名认证信息");
            }
            //查询用户信息
            SysUser sysUser = userMapper.selectUserById(realNameVO.getUserId());
            if (sysUser == null){
                throw new ServiceException("未找到用户信息");
            }
            sysUser.setRealName(realNameVO.getRealName());
            sysUser.setIdCard(realNameVO.getIdCard());
            //修改用户信息
            row = userMapper.updateUser(sysUser);
            if (row <= 0){
                throw new ServiceException("修改用户实名认证信息失败");
            }
            return AjaxResult.success();
        }
        return AjaxResult.error("未找到实名认证信息，id；" + realNameId);
    }


    /**
     * 实名认证审核不通过
     *
     * @param realNameId
     * @param remark
     * @return
     */
    @Override
    public AjaxResult failRealName(Long realNameId, String remark) {
        //校验 审核实名认证信息 权限
        checkUpdateRealNameStatusPermission();
        RealName realName = RealName.builder()
                .id(realNameId)
                .status(StatusConstant.DISABLE)
                .updateBy(SecurityUtils.getUsername())
                .updateTime(LocalDateTime.now())
                .remark("实名认证审核不通过")
                .build();
        if (remark != null){
            realName.setRemark(realName.getRemark() + ",理由：" + remark);
        }
        return realNameMapper.updateRealName(realName) > 0 ?
                AjaxResult.success() : AjaxResult.error();
    }

    /**
     * 校验 审核实名认证信息 权限
     */
    public void checkUpdateRealNameStatusPermission(){
        //查询用户信息
        SysUser sysUser = userMapper.selectUserById(SecurityUtils.getUserId());
        if (sysUser == null){
            throw new ServiceException("未找到用户信息,id: " + SecurityUtils.getUserId());
        }
        //如果不是是管理员和超级管理员
        if (!(sysUser.getRole().equals(999) || sysUser.isAdmin())){
            throw new ServiceException("没有相关权限");
        }
    }

    /**
     *  获取实名信息列表
     * @return
     */
    @Override
    public List<RealNameVO> getRealNameList() {
        return realNameMapper.getRealNameList();
    }
}
